Sanitise the trace-buffer hypervisor<->user interface.
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Mon, 31 Oct 2005 09:45:31 +0000 (10:45 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Mon, 31 Oct 2005 09:45:31 +0000 (10:45 +0100)
Signed-off-by: Keir Fraser <keir@xensource.com>
tools/libxc/xenctrl.h
tools/xentrace/xentrace.c
xen/common/trace.c
xen/include/public/trace.h
xen/include/xen/trace.h

index 42ce3097be6f1f96ff4ff0221f4b9010690c1e88..767a8ed01cb405c8e975bf72c2fd32897f7ebf12 100644 (file)
@@ -507,12 +507,10 @@ long xc_get_tot_pages(int xc_handle, uint32_t domid);
 int xc_tbuf_enable(int xc_handle, int enable);
 
 /**
- * This function sets the size of the trace buffers. Setting it to zero
- * deallocates the memory used for trace buffers, and setting it to a
- * non-zero value specifies the number of pages per cpu to allocate.
- * To change the size of an existing allocation, you must first deallocate
- * it then reallocate it. No change in size is allowed when tracing is
- * enabled; A disable call must be made first.
+ * This function sets the size of the trace buffers. Setting the size
+ * is currently a one-shot operation that may be performed either at boot
+ * time or via this interface, not both. The buffer size must be set before
+ * enabling tracing.
  *
  * @parm xc_handle a handle to an open hypervisor interface
  * @parm size the size in pages per cpu for the trace buffers
index f927a24f83c6ab1b252390030468c27247a67f3a..18105a19b7a71e59ef4b3ff1a2cbc0a795b68636 100644 (file)
@@ -23,9 +23,6 @@
 
 #include "xc_private.h"
 
-typedef struct { int counter; } atomic_t;
-#define _atomic_read(v)                ((v).counter)
-
 #include <xen/trace.h>
 
 extern FILE *stderr;
@@ -148,7 +145,7 @@ struct t_buf *map_tbufs(unsigned long tbufs_mfn, unsigned int num,
     }
 
     tbufs_mapped = xc_map_foreign_range(xc_handle, 0 /* Dom 0 ID */,
-                                        size * num, PROT_READ,
+                                        size * num, PROT_READ | PROT_WRITE,
                                         tbufs_mfn);
 
     xc_interface_close(xc_handle);
@@ -240,10 +237,7 @@ struct t_buf **init_bufs_ptrs(void *bufs_mapped, unsigned int num,
  * mapped in user space.  Note that the trace buffer metadata contains machine
  * pointers - the array returned allows more convenient access to them.
  */
-struct t_rec **init_rec_ptrs(unsigned long tbufs_mfn,
-                             struct t_buf *tbufs_mapped,
-                             struct t_buf **meta,
-                             unsigned int num)
+struct t_rec **init_rec_ptrs(struct t_buf **meta, unsigned int num)
 {
     int i;
     struct t_rec **data;
@@ -256,38 +250,11 @@ struct t_rec **init_rec_ptrs(unsigned long tbufs_mfn,
     }
 
     for ( i = 0; i < num; i++ )
-        data[i] = (struct t_rec *)(meta[i]->rec_addr - (tbufs_mfn<<XC_PAGE_SHIFT) /* XXX */
-                                   + (unsigned long)tbufs_mapped);
+        data[i] = (struct t_rec *)(meta[i] + 1);
 
     return data;
 }
 
-/**
- * init_tail_idxs - initialise an array of tail indexes
- * @bufs:           array of pointers to trace buffer metadata
- * @num:            number of trace buffers
- *
- * The tail indexes indicate where we're read to so far in the data array of a
- * trace buffer.  Each entry in this table corresponds to the tail index for a
- * particular trace buffer.
- */
-unsigned long *init_tail_idxs(struct t_buf **bufs, unsigned int num)
-{
-    int i;
-    unsigned long *tails = calloc(num, sizeof(unsigned int));
-    if ( tails == NULL )
-    {
-        PERROR("Failed to allocate memory for tail pointers\n");
-        exit(EXIT_FAILURE);
-    }
-    
-    for ( i = 0; i<num; i++ )
-        tails[i] = _atomic_read(bufs[i]->rec_idx);
-
-    return tails;
-}
-
 /**
  * get_num_cpus - get the number of logical CPUs
  */
@@ -329,7 +296,6 @@ int monitor_tbufs(FILE *logfile)
     struct t_buf **meta;         /* pointers to the trace buffer metadata    */
     struct t_rec **data;         /* pointers to the trace buffer data areas
                                   * where they are mapped into user space.   */
-    unsigned long *cons;         /* store tail indexes for the trace buffers */
     unsigned long tbufs_mfn;     /* mfn of the tbufs                         */
     unsigned int  num;           /* number of trace buffers / logical CPUS   */
     unsigned long size;          /* size of a single trace buffer            */
@@ -346,19 +312,22 @@ int monitor_tbufs(FILE *logfile)
     size_in_recs = (size - sizeof(struct t_buf)) / sizeof(struct t_rec);
 
     /* build arrays of convenience ptrs */
-    meta  = init_bufs_ptrs (tbufs_mapped, num, size);
-    data  = init_rec_ptrs  (tbufs_mfn, tbufs_mapped, meta, num);
-    cons  = init_tail_idxs (meta, num);
+    meta  = init_bufs_ptrs(tbufs_mapped, num, size);
+    data  = init_rec_ptrs(meta, num);
 
     /* now, scan buffers for events */
     while ( !interrupted )
     {
-        for ( i = 0; ( i < num ) && !interrupted; i++ )
-            while( cons[i] != _atomic_read(meta[i]->rec_idx) )
+        for ( i = 0; (i < num) && !interrupted; i++ )
+        {
+            while ( meta[i]->cons != meta[i]->prod )
             {
-                write_rec(i, data[i] + cons[i], logfile);
-                cons[i] = (cons[i] + 1) % size_in_recs;
+                rmb(); /* read prod, then read item. */
+                write_rec(i, data[i] + meta[i]->cons % size_in_recs, logfile);
+                mb(); /* read item, then update cons. */
+                meta[i]->cons++;
             }
+        }
 
         nanosleep(&opts.poll_sleep, NULL);
     }
@@ -366,7 +335,6 @@ int monitor_tbufs(FILE *logfile)
     /* cleanup */
     free(meta);
     free(data);
-    free(cons);
     /* don't need to munmap - cleanup is automatic */
     fclose(logfile);
 
index becdaff85348804170d35d9a005b12ed88e1c86b..9746b75102de0292739ac77f5da13e459aac8dd6 100644 (file)
@@ -37,6 +37,8 @@ integer_param("tbuf_size", opt_tbuf_size);
 
 /* Pointers to the meta-data objects for all system trace buffers */
 static struct t_buf *t_bufs[NR_CPUS];
+static struct t_rec *t_recs[NR_CPUS];
+static int nr_recs;
 
 /* a flag recording whether initialization has been done */
 /* or more properly, if the tbuf subsystem is enabled right now */
@@ -70,6 +72,8 @@ static int alloc_trace_bufs(void)
 
     nr_pages = num_online_cpus() * opt_tbuf_size;
     order    = get_order_from_pages(nr_pages);
+    nr_recs  = (opt_tbuf_size * PAGE_SIZE - sizeof(struct t_buf)) /
+        sizeof(struct t_rec);
     
     if ( (rawbuf = alloc_xenheap_pages(order)) == NULL )
     {
@@ -84,13 +88,11 @@ static int alloc_trace_bufs(void)
     for_each_online_cpu ( i )
     {
         buf = t_bufs[i] = (struct t_buf *)&rawbuf[i*opt_tbuf_size*PAGE_SIZE];
-        
-        _atomic_set(buf->rec_idx, 0);
-        buf->rec_num  = (opt_tbuf_size * PAGE_SIZE - sizeof(struct t_buf))
-                        / sizeof(struct t_rec);
-        buf->rec      = (struct t_rec *)(buf + 1);
-        buf->rec_addr = __pa(buf->rec);
+        buf->cons = buf->prod = 0;
+        buf->nr_recs = nr_recs;
+        t_recs[i] = (struct t_rec *)(buf + 1);
     }
+
     return 0;
 }
 
@@ -223,9 +225,9 @@ int tb_control(dom0_tbufcontrol_t *tbc)
 void trace(u32 event, unsigned long d1, unsigned long d2,
            unsigned long d3, unsigned long d4, unsigned long d5)
 {
-    atomic_t old, new, seen;
     struct t_buf *buf;
     struct t_rec *rec;
+    unsigned long flags;
 
     BUG_ON(!tb_init_done);
 
@@ -249,17 +251,15 @@ void trace(u32 event, unsigned long d1, unsigned long d2,
 
     buf = t_bufs[smp_processor_id()];
 
-    do
+    local_irq_save(flags);
+
+    if ( (buf->prod - buf->cons) >= nr_recs )
     {
-        old = buf->rec_idx;
-        _atomic_set(new, (_atomic_read(old) + 1) % buf->rec_num);
-        seen = atomic_compareandswap(old, new, &buf->rec_idx);
+        local_irq_restore(flags);
+        return;
     }
-    while ( unlikely(_atomic_read(seen) != _atomic_read(old)) );
-
-    wmb();
 
-    rec = &buf->rec[_atomic_read(old)];
+    rec = &t_recs[smp_processor_id()][buf->prod % nr_recs];
     rdtscll(rec->cycles);
     rec->event   = event;
     rec->data[0] = d1;
@@ -267,6 +267,11 @@ void trace(u32 event, unsigned long d1, unsigned long d2,
     rec->data[2] = d3;
     rec->data[3] = d4;
     rec->data[4] = d5;
+
+    wmb();
+    buf->prod++;
+
+    local_irq_restore(flags);
 }
 
 /*
index 9b3c4d5c0c698f5855741c929bf9a88e75fcc501..47b4bdd18988590052724b106485fc4e5a448fe9 100644 (file)
@@ -65,13 +65,10 @@ struct t_rec {
  * field, indexes into an array of struct t_rec's.
  */
 struct t_buf {
-    /* Used by both Xen and user space. */
-    atomic_t      rec_idx;   /* the next record to save to */
-    unsigned int  rec_num;   /* number of records in this trace buffer  */
-    /* Used by Xen only. */
-    struct t_rec  *rec;      /* start of records */
-    /* Used by user space only. */
-    unsigned long rec_addr;  /* machine address of the start of records */
+    unsigned int  cons;      /* Next item to be consumed by control tools. */
+    unsigned int  prod;      /* Next item to be produced by Xen.           */
+    unsigned int  nr_recs;   /* Number of records in this trace buffer.    */
+    /* 'nr_recs' records follow immediately after the meta-data header.    */
 };
 
 #endif /* __XEN_PUBLIC_TRACE_H__ */
index e09051c2591e9715d4691ce3a10b7b4d828b1d22..a3e6b55654de58d211abf90bde8fc2038ce3a67d 100644 (file)
@@ -24,7 +24,6 @@
 #define __XEN_TRACE_H__
 
 #include <xen/config.h>
-#include <asm/atomic.h>
 #include <public/dom0_ops.h>
 #include <public/trace.h>